﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media;
using KadalaSpree.XCore;
using Zeta.Common;
using Zeta.Common.Xml;
using KadalaSpree.XCore.Converters;

namespace KadalaSpree
{
    class Config
    {
        private static readonly Dictionary<string, Window> Windows = new Dictionary<string, Window>();

        public static Window GetDisplayWindow(string xamlFileName, XmlSettings settingsInstance, string windowTitle = "")
        {
            if (Windows.ContainsKey(xamlFileName) && Windows[xamlFileName] != null)
            {
                return Windows[xamlFileName];
            }
            return CreateDisplayWindow(xamlFileName, settingsInstance, windowTitle);
        }

        internal static Window CreateDisplayWindow (string xamlFileName, XmlSettings settingsInstance, string windowTitle)
        {
            var configWindow = new Window();

            try
            {
                var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
                var pluginPath = Path.Combine(assemblyPath, "plugins");
                
                //var xamlInterfaceFile = string.Empty;

                if (assemblyPath == null)
                    return null;

                var xamlInterfaceFile = GetFile(pluginPath, xamlFileName);

                if (!File.Exists(xamlInterfaceFile))
                {
                    return null;
                }

                X.Logger.Instance.Debug("Creating New {0} Window {0}", windowTitle);

                var xamlContent = File.ReadAllText(xamlInterfaceFile);

                configWindow.DataContext = settingsInstance;

                var mainControl = (UserControl) XamlReader.Load(new MemoryStream(Encoding.UTF8.GetBytes(xamlContent)));

                Action<object, CancelEventArgs> closingHandler = delegate(object sender, CancelEventArgs e)
                {
                    if (!CloseAllowed)
                    {
                        settingsInstance.Save();
                        configWindow.Visibility = Visibility.Hidden;
                        e.Cancel = true;
                        X.Logger.Instance.Debug("Hiding {0} Window", windowTitle);
                    }
                    else
                    {
                        X.Logger.Instance.Debug("Closing {0} Window", windowTitle);
                    }
                            
                };

                configWindow.Content = mainControl;
                configWindow.Width = 370;
                configWindow.Height = 600;
                configWindow.Title = windowTitle;
                configWindow.Closing += (s,e) => closingHandler(s,e);

                configWindow.Owner = Application.Current.MainWindow;
                configWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;

                Application.Current.MainWindow.Closing += Application_Closing;

                Windows.Add(xamlFileName, configWindow);

                return configWindow;
                
            }
            catch (Exception ex)
            {
                X.Logger.Instance.Debug("Failed to load Config UI {0}", ex);
            }
            return null;
        }

        protected static string GetFile (string startDirectory, string needles)
        {
            return GetFile(startDirectory, new List<string>() { needles });
        }

        protected static string GetFile(string startDirectory, ICollection<string> needles)
        {
            var dirExcludes = new HashSet<string>
            {
                ".svn",
                "obj",
                "bin",
                "debug"
            };

            var queue = new Queue<string>();

            queue.Enqueue(startDirectory);

            // Get the file or directory name from path
            Func<string, string> last = input => input.Split('\\').Last().ToLower();

            // Check if string is within list of valid strings (case-insensitive)
            Func<IEnumerable<string>, string, bool> contains = (haystack,needle) =>
            {
                return haystack.Contains(needle, StringComparer.Create(Thread.CurrentThread.CurrentCulture, true));
            };

            while (queue.Count > 0)
            {
                startDirectory = queue.Dequeue();
                try
                {
                    foreach (var subDir in Directory.GetDirectories(startDirectory))
                    {
                        if (contains(dirExcludes, last(subDir))) continue;
                        //X.Logger.Log("Searching Directory {0}", subDir);
                        queue.Enqueue(subDir);
                    }
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine(ex);
                }
                string[] files = null;
                try
                {
                    files = Directory.GetFiles(startDirectory);
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine(ex);
                }
                if (files != null)
                {
                    foreach (var filePath in files)
                    {
                        //X.Logger.Log("Comparing File {0} match={1}", filePath, contains(needles, last(filePath)));
                        if (!contains(needles, last(filePath))) continue;
                        return filePath;
                    }
                }
            }
            return string.Empty;
        }

        public static bool CloseAllowed { get; set; }

        private static void Application_Closing(object sender, CancelEventArgs e)
        {
            X.Logger.Instance.Debug("Application_Closing");
            CloseAllowed = true;   
            Windows.ForEach(w => w.Value.Close());   
            Windows.Clear();
        }

    }

}


